package lucava.metamodel.java;

import java.util.ArrayList;
import java.util.List;
import lucava.metamodel.java.type.MetaType;
import lucava.metamodel.java.type.MetaTypeClasse;
import lucava.metamodel.java.visitor.IJavaMetaModelVisitor;

public class MetaClasse extends MetaClassifier {

	/**
	 * SuperClasse de la classe.
	 */
	protected MetaClasse mExtends = null;

	/**
	 * Liste des interfaces implémentées par la classe.
	 */
	protected final List<MetaInterface> mImplements = new ArrayList<MetaInterface>();

	/**
	 * Liste des attributs de la classe.
	 */
	protected final List<Attribute> mAttributes = new ArrayList<Attribute>();

	/**
	 * Liste des méthode de la classe.
	 */
	protected final List<Methode> mMethods = new ArrayList<Methode>();

	/**
	 * Booléen indiquant si la classe possède le constructeur par défaut.
	 */
	private boolean mHasDefaultConstructor = true;

	/**
	 * Constructeur par défaut.
	 */
	public MetaClasse() {
		this("NewClasse");
	}

	/**
	 * Constructeur.
	 * 
	 * @param aName
	 *            , Nom de la Classe.
	 */
	public MetaClasse(String aName) {
		super(aName);
	}

	/**
	 * Retourne la SuperClasse de la Classe.
	 */
	public MetaClasse getExtends() {
		return mExtends;
	}

	/**
	 * Assigne la SuperClasse de la Classe.
	 * 
	 * @param aClasse
	 *            , SuperClasse à assigner.
	 */
	public void setExtends(MetaClasse aClasse) {
		this.mExtends = aClasse;
	}

	/**
	 * Assigne la SuperClasse de la Classe.
	 * 
	 * @param aClasseName
	 *            , Nom de la SuperClasse à assigner.
	 */
	public void setExtends(String aClasseName) {
		MetaClasse extendedClass = new MetaClasse(aClasseName);
		this.setExtends(extendedClass);
	}

	/**
	 * Ajoute une interface implémentée par la Classe.
	 * 
	 * @param anInterface
	 *            , Interface à ajouter.
	 */
	public void addImplements(MetaInterface anInterface) {
		this.mImplements.add(anInterface);
	}

	/**
	 * Ajoute une interface implémentée par la Classe.
	 * 
	 * @param anInterfaceName
	 *            , Nom de l'Interface à ajouter.
	 */
	public void addImplements(String anInterfaceName) {
		MetaInterface implementedInterface = new MetaInterface(anInterfaceName);
		this.addImplements(implementedInterface);
	}

	/**
	 * Ajoute un attribut à la Classe.
	 * 
	 * @param anAttribute
	 *            , Attribut à ajouter.
	 */
	public void removeAttribute(Attribute anAttribute) {
		this.mAttributes.remove(anAttribute);
	}

	/**
	 * Ajoute une méthode à la Classe.
	 * 
	 * @param aMethode
	 *            , Méthode à ajouter.
	 */
	public void addMethod(Methode aMethode) {
		this.mMethods.add(aMethode);
	}

	/**
	 * Supprime une méthode à la Classe.
	 * 
	 * @param aMethode
	 *            , Méthode à supprimer.
	 */
	public void removeMethode(Methode aMethode) {
		this.mMethods.remove(aMethode);
	}

	/**
	 * Méthode d'acceptation du visiteur de MetaModelJava.
	 * 
	 * @param aVisitor
	 *            , Visiteur de MetaModelJava.
	 */
	public void accept(IJavaMetaModelVisitor aVisitor) {
		aVisitor.visitClasse(this);
	}

	/**
	 * Retourne la liste des Interface implémentées par la Classe.
	 */
	public List<MetaInterface> getImplements() {
		return mImplements;
	}

	/**
	 * Retourne la liste des méthodes de la Classe.
	 */
	public List<Methode> getMethods() {
		return mMethods;
	}

	/**
	 * Retourne la liste des attributs de la Classe.
	 */
	public List<Attribute> getAttributes() {
		return mAttributes;
	}

	/**
	 * Ajoute un attribut à la Classe.
	 * 
	 * @param anAttribute
	 *            , Attribut à ajouter.
	 */
	public void addAttribute(Attribute anAttribute) {
		this.mAttributes.add(anAttribute);
	}

	/**
	 * Assigne un commentaire à la Classe.
	 */
	@Override
	public void setComment(String aComment) {
		this.mComments.setComment(aComment);
	}

	/**
	 * Ajout un attribut à la classe.
	 * 
	 * @param aType
	 *            , Type de l'attribut.
	 * @param aName
	 *            , Nom de l'attribut.
	 */
	public void addAttribute(MetaType aType, String aName) {
		this.addAttribute(new Attribute(aType, aName));
	}

	/**
	 * Ajout un attribut à la classe.
	 * 
	 * @param aClasse
	 *            , Classe de l'attribut.
	 * @param aName
	 *            , Nom de l'attribut.
	 */
	public void addAttribute(MetaClasse aClasse, String aName) {
		this.addAttribute(new Attribute(new MetaTypeClasse(aClasse), aName));
	}

	/**
	 * Ajoute un attribut à la classe.
	 * 
	 * @param aClasse
	 *            , Classe de l'attribut.
	 * @param aName
	 *            , Nom de l'attribut.
	 * @param aCardinality
	 *            , Cardinalité de l'attribut.
	 */
	public void addAttribute(MetaClasse aClasse, String aName,
			String aCardinality) {
		this.addAttribute(new Attribute(new MetaTypeClasse(aClasse), aName,
				aCardinality));
	}

	/**
	 * Indique si la classe possède le constructeur par défaut.
	 */
	public boolean hasDefaultConstructor() {
		return mHasDefaultConstructor;
	}

	/**
	 * Assigne si la classe possède le constructeur par défaut.
	 */
	public void enableDefaultConstructor(boolean mHasDefaultConstructor) {
		this.mHasDefaultConstructor = mHasDefaultConstructor;
	}

}
